/*
 * (C) Copyright 2012, by Tim Xie.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.superapk.diamond.sqllite;

import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;

import com.superapk.diamond.sqllite.exception.DeleteSqlException;
import com.superapk.diamond.sqllite.exception.SqlException;
import com.superapk.diamond.sqllite.exception.UpdateSqlException;
import com.superapk.diamond.util.LogUtil;

/**
 * SQLLite语法生成
 * 
 * @author     Tim Xie [tim.xie2008@gmail.com]
 * @date       2013-3-14
 * 
 */

class SQLBuilder {
	
	private final static String SQL_INT_TYPE = "INTEGER";
	
	private final static String SQL_LONG_TYPE = "LONG";
	
	private final static String SQL_FLOAT_TYPE = "FLOAT";
	
	private final static String SQL_STRING_TYPE = "TEXT";
	
	private final static String SQL_DATE_TYPE = "DATE";
	
	private final static String SQL_UNKNOW_TYPE = "unknow";
	
	/**
	 * 生成创建表格的SQL
	 * @param tableClass
	 * @return
	 */
	static String buildCreatTableSQL(Object tableClass){
		TableInfo tableInfo = TableInfo.getTableInfo(tableClass.getClass());
		StringBuffer buffer = new StringBuffer();
		buffer.append("CREATE TABLE IF NOT EXISTS ");
		buffer.append(tableInfo.getTableName());
		buffer.append(" (");
		//主键
		FieldInfo primaryKey = tableInfo.getPrimaryKey();
		if(primaryKey != null){
			String dataTypeStr = getSQLDataTypeStr(primaryKey.getDataType());
			buffer.append(primaryKey.getColumnName()).append(" ").append(dataTypeStr).append(" PRIMARY KEY,");
		}else{
			buffer.append("_id INTEGER PRIMARY KEY,");
		}
		//
		HashMap<String, FieldInfo> fieldMap = tableInfo.getFieldInfoMap();
		if(fieldMap != null && fieldMap.size() > 0){
			Collection<FieldInfo> fieldInfos = fieldMap.values();
			for(FieldInfo fieldInfo : fieldInfos){
				//字段名称
				buffer.append(fieldInfo.getColumnName());
				//字段类型
				String dataTypeStr = getSQLDataTypeStr(fieldInfo.getDataType());
				buffer.append(" ").append(dataTypeStr);
				//字段默认值
				String defaultValue = fieldInfo.getDefaultValue();
				if(defaultValue != null && !defaultValue.equals("")){
					buffer.append(" DEFAULT ").append("'").append(defaultValue).append("'");
				}
				//是否唯一
				boolean unique = fieldInfo.isUnique();
				if(unique){
					buffer.append(" UNIQUE ");
				}
				buffer.append(",");
			}
		}
		buffer.deleteCharAt(buffer.length() - 1);
		buffer.append(");");
		
		return buffer.toString();
	}
	
	/**
	 * 根据Java实例生成插入数据的sql
	 * 
	 * @param entity
	 * @return
	 */
	static String buildInsertSql(Object entity){
		TableInfo tableInfo = TableInfo.getTableInfo(entity.getClass());
		//主键
		FieldInfo primaryKeyFI = tableInfo.getPrimaryKey();
		//所有属性名
		HashMap<String, FieldInfo> propertysMap = tableInfo.getFieldInfoMap();
		//所有有值的字段名
		HashMap<String, Object> columnKeyValues = new HashMap<String, Object>();
		Collection<FieldInfo> propertys = propertysMap.values();
		for(FieldInfo tmpPro : propertys){
			//数据库列名
			String column = tmpPro.getColumnName();
			//插入的值
			Object value = tmpPro.getValue(entity);
			if(value != null){
				columnKeyValues.put(column, value);
			}
		}
		//拼凑插入SQL语句
		StringBuffer buffer = new StringBuffer();
		buffer.append("INSERT INTO ");
		buffer.append(tableInfo.getTableName());
		buffer.append(" ( ");
		Set<String> columnKeys = columnKeyValues.keySet();
		Iterator<String> iterator = columnKeys.iterator();
		while(iterator.hasNext()){
			Object key = iterator.next();
			buffer.append(key).append(",");
		}
		buffer.deleteCharAt(buffer.length() - 1);
		buffer.append(") VALUES ( ");
		iterator = columnKeys.iterator();
		while(iterator.hasNext()){
			Object key = iterator.next();
			buffer.append("'").append(columnKeyValues.get(key)).append("'").append(",");
		}
		buffer.deleteCharAt(buffer.length() - 1);
		buffer.append(");");
		
		return buffer.toString();
	}
	
	/**
	 * 根据Java实例生成更新数据的sql
	 * @param entity
	 * @param where
	 * @param whereArgs
	 * @return
	 */
	static String buildUpdateSql(Object entity) throws UpdateSqlException{
		TableInfo tableInfo = TableInfo.getTableInfo(entity.getClass());
		//主键
		FieldInfo primaryKeyFI = tableInfo.getPrimaryKey();
		Object idValue = primaryKeyFI.getValue(entity);
		if(idValue == null){
			throw new UpdateSqlException("primary key value is null.");
		}
		//所有有值的字段名
		HashMap<String, Object> columnKeyValues = getColumnKeyValues(entity);
		if(columnKeyValues == null || columnKeyValues.size() == 0){
			throw new UpdateSqlException("entity must be contains property.");
		}
		//拼凑插入SQL语句
		StringBuffer buffer = new StringBuffer();
		buffer.append("UPDATE ");
		buffer.append(tableInfo.getTableName());
		buffer.append(" SET ( ");
		Set<String> columnKeys = columnKeyValues.keySet();
		Iterator<String> iterator = columnKeys.iterator();
		while(iterator.hasNext()){
			Object key = iterator.next();
			buffer.append(key).append(",");
		}
		buffer.deleteCharAt(buffer.length() - 1);
		buffer.append(") VALUES ( ");
		iterator = columnKeys.iterator();
		while(iterator.hasNext()){
			Object key = iterator.next();
			buffer.append("'").append(columnKeyValues.get(key)).append("'").append(",");
		}
		buffer.deleteCharAt(buffer.length() - 1);
		buffer.append(" WHERE ").append(primaryKeyFI.getColumnName());
		buffer.append("=").append("'");
		buffer.append(idValue);
		buffer.append("'");
		buffer.append(");");
		
		return buffer.toString();
	}
	
	/**
	 * 根据Java实例生成更新数据的sql
	 * @param entity
	 * @param where
	 * @param whereArgs
	 * @return
	 */
	static String buildUpdateByWhereSql(Object entity,String where) throws UpdateSqlException{
		TableInfo tableInfo = TableInfo.getTableInfo(entity.getClass());
		//所有属性名
		HashMap<String, FieldInfo> propertysMap = tableInfo.getFieldInfoMap();
		//所有有值的字段名
		HashMap<String, Object> columnKeyValues = new HashMap<String, Object>();
		Collection<FieldInfo> propertys = propertysMap.values();
		for(FieldInfo tmpPro : propertys){
			//数据库列名
			String column = tmpPro.getColumnName();
			//插入的值
			Object value = tmpPro.getValue(entity);
			if(value != null){
				columnKeyValues.put(column, value);
			}
		}
		if(columnKeyValues == null || columnKeyValues.size() == 0){
			throw new UpdateSqlException("entity must be contains property.");
		}
		if(where == null || where.equals("")){
			throw new UpdateSqlException("param where must be not null.");
		}
		//拼凑插入SQL语句
		StringBuffer buffer = new StringBuffer();
		buffer.append("UPDATE ");
		buffer.append(tableInfo.getTableName());
		buffer.append(" SET ( ");
		Set<String> columnKeys = columnKeyValues.keySet();
		Iterator<String> iterator = columnKeys.iterator();
		while(iterator.hasNext()){
			Object key = iterator.next();
			buffer.append(key).append(",");
		}
		buffer.deleteCharAt(buffer.length() - 1);
		buffer.append(") VALUES ( ");
		iterator = columnKeys.iterator();
		while(iterator.hasNext()){
			Object key = iterator.next();
			buffer.append("'").append(columnKeyValues.get(key)).append("'").append(",");
		}
		buffer.deleteCharAt(buffer.length() - 1);
		buffer.append(" WHERE ").append(where);
		buffer.append(");");
		
		return buffer.toString();
	}
	
	/**
	 * 根据一个实例删除数据库的数据，该实例的主键必须不能为空
	 * @param entity
	 * @return
	 * @throws DeleteSqlException
	 */
	static String buildDeleteSql(Object entity) throws DeleteSqlException{
		TableInfo tableInfo = TableInfo.getTableInfo(entity.getClass());
		//主键
		FieldInfo primaryKeyFI = tableInfo.getPrimaryKey();
		Object idValue = primaryKeyFI.getValue(entity);
		if(idValue == null){
			throw new DeleteSqlException("primary key is null.");
		}
		//拼凑插入SQL语句
		StringBuffer buffer = new StringBuffer();
		buffer.append("DELETE FROM ");
		buffer.append(tableInfo.getTableName());
		buffer.append(" WHERE ").append(primaryKeyFI.getColumnName());
		buffer.append("=").append("'");
		buffer.append(idValue);
		buffer.append("'");
		buffer.append(");");
		
		return buffer.toString();
	}
	
	static ExecSQL buildQuerySqlById(Object entity,int id) throws SqlException{
		ExecSQL execSQL = new ExecSQL();
		TableInfo tableInfo = TableInfo.getTableInfo(entity.getClass());
		//主键
		FieldInfo primaryKeyFI = tableInfo.getPrimaryKey();
		//拼凑插入SQL语句
		StringBuffer buffer = new StringBuffer();
		buffer.append("SELECT * FROM ");
		buffer.append(tableInfo.getTableName());
		buffer.append(" WHERE ").append(primaryKeyFI.getColumnName());
		buffer.append("=").append("'");
		buffer.append("?");
		buffer.append("'");
		buffer.append(");");
		
		execSQL.setExecSql(buffer.toString());
		execSQL.addBindArgs(id);
		
		return execSQL;
	}
	
	/**
	 * 获取实例的Key和Value
	 * @param entity
	 * @return
	 */
	static HashMap<String, Object> getColumnKeyValues(Object entity){
		TableInfo tableInfo = TableInfo.getTableInfo(entity.getClass());
		HashMap<String, FieldInfo> propertysMap = tableInfo.getFieldInfoMap();
		HashMap<String, Object> columnKeyValues = new HashMap<String, Object>();
		Collection<FieldInfo> propertys = propertysMap.values();
		for(FieldInfo tmpPro : propertys){
			//数据库列名
			String column = tmpPro.getColumnName();
			//插入的值
			Object value = tmpPro.getValue(entity);
			if(value != null){
				columnKeyValues.put(column, value);
			}
		}
		return columnKeyValues;
	}
	
	/**
	 * 把Java的类型转成SQL类型
	 * @param dataType
	 * @return
	 */
	private static String getSQLDataTypeStr(Class<?> dataType){
		String dataTypeStr = null;
		if(dataType == int.class || dataType == Integer.class
				|| dataType == short.class || dataType == Short.class){
			dataTypeStr = SQL_INT_TYPE;
		}else if(dataType == long.class || dataType == Long.class){
			dataTypeStr = SQL_LONG_TYPE;
		}else if(dataType == float.class || dataType == Float.class
				|| dataType == double.class || dataType == Double.class){
			dataTypeStr = SQL_FLOAT_TYPE;
		}else if(dataType == String.class || dataType == CharSequence.class){
			dataTypeStr = SQL_STRING_TYPE;
		}else if(dataType == Date.class){
			dataTypeStr = SQL_DATE_TYPE;
		}else{
			dataTypeStr = SQL_UNKNOW_TYPE;
			LogUtil.e("dataType is nuknow type.");
		}
		return dataTypeStr;
	}
	
}
